/************************************************************************
 * @file PluginContext.h
 * @author Ian Chen
 * @version 1.0
 *
 * @section LICENSE
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details at
 * http://www.gnu.org/licenses/lgpl.html
 *
 ************************************************************************/
#ifndef PLUGINCONTEXT_H
#define PLUGINCONTEXT_H

#include <QObject>

#include <plugin/plugin_global.h>
#include <plugin/service/AbstractService.h>

namespace antu
{
namespace plugin
{
//! Object to hold environment context for plug-ins
/*! PluginContext defines the environment in which a plugin is loaded. Plugins
    can retrieve essential information from the context object during load time
    the framework is not responsible for releaseing context objects. because
    context object is created within the application, plugin should not attempt
    to delete context object, and all plugins including the framework plugin
    share the same context instance.

    PluginContext will not attemp to release objects in environment context, uses
    should manually delete those objects.
 */
class PLUGINSHARED_EXPORT PluginContext : public QObject
{
    Q_OBJECT

private:
    //! Plugin environment context objects, such as UI managers etc.
    /*! Globally available context objects for plug-ins. Objects such
        as UI containers etc. can be placed here.
     */
    map<QString, QObject*> m_oEnvironmentContext;

    //! Plugin settings
    /*! Settings that should be globally available should be put in here.
     */
    map<QString, QVariant> m_oEnvironmentSettings;

    //! Application startup path
    QString m_sApplicationPath;

    //! Plugin download path
    QString m_sDownloadPath;

    //! Plugin path
    /*! This is where downloaded plug-ins are to temporarily stored. Auto-update
        programs should look into this folder to update the application
     */
    QString m_sPluginPath;

    //! Framework application group
    /*! This is used to tag plugin categories. A plugin can have multiple application
        group tags, but an application can belong to only one group. Such tags are used
        to determine what plug-ins should be loaded for an application. Plug-ins having
        the tag "ATTGNRC" are loaded regardless of the application tag, i.e. these
        plug-ins are considered universally applicable.
     */
    QString m_sApplicationGroup;

    //! Directory where translation files are stored.
    QString m_sLanguagePath;

    QString m_sApplicationName;

    Q_DISABLE_COPY(PluginContext)

public:
    //! Default constructor
    PluginContext();

    //! Constructs a context object with environment objects
    /*! Constructs a context object with environment objects.
      \param Context environment context
     */
    PluginContext(const map<QString, QObject*>& context);

    //! Constructs a context object with environment objects and global settings
    /*! Constructs a context object with environment objects and global settings
      \param Context environment context
      \param Settings environment settings
     */
    PluginContext(const map<QString, QObject*>& context, const map<QString, QVariant>& settings);

    PluginContext(const map<QString, QVariant>& settings, const QString& path = QString());

    //! Destructor for context object.
    /*! Destructor for context object. Notice that PluginContext will not explicitly release
        memory space allocated for context objects. It is the responsibility of the main
        application to release these objects, as these objects may refer to Qt's UI objects.
        Deletion of these objects in PluginContext destructor could introduce complexity.
     */
    virtual ~PluginContext();

    //! Retrieves context object
    /*! Retrieves context object based on object name.
      \param name Name of context object to be retrieved.
      \return Pointer to context object, null if object of the specified name is not found.
     */
    QObject* operator[](const QString& name);

    //! Retrieves a const context object based on name
    /*! Retrieves a const context object based on object name.
      \param name Name of context object to be retrieved
      \return Const pointer to context object, null if name not found
     ************************************************************************/
    QObject* contextObjectAt(const QString& name) const;

    bool addContextObject(const QString& name, QObject* pContextObject);

    //! Retrieves setting based on setting name
    /*! Retrieves setting based on setting name.
      \param name Name of setting object to be retrieved.
      \return Corresponding setting object, empty QVariant object if name not found
     */
    QVariant settingAt(const QString& name) const;

    bool addContextSetting(const QString& name, const QVariant& value);

    //! Application startup path.
    /*! This is where the main application executable and the plugin dlls
        are located.
      \return
     */
    QString applicationPath() const;

    //! Plugin download path
    /*! Retrieves the installation path of the application, this is where the
        downloaded plugin files are stored.
      \return Directory where the downloaded plugin files are stored.
     */
    QString installationPath() const;

    //! Plugin description file path
    /*! Retrieves the path where plugin description files are stored.
      \return Directory where the plugin description files are stored.
      \sa applicationPath(), pluginPath(), languagePath()
     */
    QString pluginPath() const;

    //! Sets application path
    /*! Sets application startup path. This method also sets the folder where
        new plugins are downloaded, the folder where plugin description files
        are stored, and the folder where translation files are stored.
      \param path Startup path to be set
      \sa applicationPath(), installationPath(), languagePath(), pluginPath()
     */
    void setApplicationPath(const QString& path);

    //! Framework application group
    /*! This is used to tag plugin categories. A plugin can have multiple application
        group tags, but an application can belong to only one group. Such tags are used
        to determine what plug-ins should be loaded for an application. Plug-ins having
        the tag "ATTGNRC" are loaded regardless of the application tag, i.e. these
        plug-ins are considered universally applicable.
      \return Application startup path
      \sa setApplicationGroup()
    */
    QString applicationGroup() const;

    //! Sets application group of the main application
    /*! Sets application group of the main application.
      \param group name of application group
      \sa applicationGroup()
     */
    void setApplicationGroup(const QString& group);

    //! Directory where translation files are stored.
    /*! Directory where translation files are stored. Plug-ins should
        load translation files from this folder
      \return Directory where translation files are stored.
      \sa applicationPath(), installationPath(), pluginPath()
     */
    QString languagePath();

    QString applicationName() const;

    void setApplicationName(const QString& name);
};
}
}

#endif // PLUGINCONTEXT_H
